package redis

import (
	"encoding/binary"
	"gitee.com/Cauchy_AQ/gokv"
)

// ============================= Hash 数据结构 ========================= //

// HSet 哈希 set 操作
func (r *RedisDataStruct) HSet(key, field, value []byte) (bool, error) {
	// 查找元数据 metadata
	meta, err := r.findAndCreateMetadata(key, Hash)
	if err != nil {
		return false, err
	}

	// 编码
	internalKey := hashInternalKey{
		key:     key,
		version: meta.version,
		field:   field,
	}
	encKey := internalKey.encode()

	// 查询 key 是否存在
	_, err = r.db.Get(encKey)
	var exists bool = true
	if err != nil && err != gokv.ErrKeyNotFound {
		return false, err
	}
	if err == gokv.ErrKeyNotFound {
		exists = false
	}

	// 原子操作
	writeBatchOpts := gokv.DefaultWriteBatchOptions
	wb := r.db.NewWriteBatch(&writeBatchOpts)
	if !exists {
		// 不存在，新增域
		meta.size += 1
		// 重新编码存入元信息
		_ = wb.Put(key, meta.encode())
	}
	// 不管是否存在，都会对域值修改
	_ = wb.Put(encKey, value)
	if err := wb.Commit(); err != nil {
		return false, err
	}
	return !exists, nil
}

// HGet 哈希 get 操作
func (r *RedisDataStruct) HGet(key, field []byte) ([]byte, error) {
	// 查找元数据 metadata
	meta, exist, err := r.findMetadata(key, Hash)
	if err != nil {
		return nil, err
	}
	if !exist {
		return nil, gokv.ErrKeyNotFound
	}

	internalKey := hashInternalKey{
		key:     key,
		version: meta.version,
		field:   field,
	}
	encKey := internalKey.encode()

	return r.db.Get(encKey)
}

func (r *RedisDataStruct) HDel(key, field []byte) (bool, error) {
	// 查找元数据 metadata
	meta, exist, err := r.findMetadata(key, Hash)
	if err != nil {
		return false, err
	}
	if !exist {
		return false, gokv.ErrKeyNotFound
	}
	internalKey := hashInternalKey{
		key:     key,
		version: meta.version,
		field:   field,
	}
	encKey := internalKey.encode()

	var exists bool = true
	if _, err := r.db.Get(encKey); err == gokv.ErrKeyNotFound {
		exists = false
	}

	if exists {
		// key 存在则执行删除
		writeBatchOpts := gokv.DefaultWriteBatchOptions
		wb := r.db.NewWriteBatch(&writeBatchOpts)
		meta.size -= 1
		_ = wb.Delete(encKey)
		_ = wb.Put(key, meta.encode())

		if meta.size == 0 {
			_ = wb.Delete(key)
		}
		if err := wb.Commit(); err != nil {
			return false, err
		}
	}
	return exists, nil
}

func (r *RedisDataStruct) HExists(key, field []byte) (bool, error) {
	meta, exist, err := r.findMetadata(key, Hash)
	if err != nil {
		return false, err
	}
	if !exist {
		return false, gokv.ErrKeyNotFound
	}

	internalKey := hashInternalKey{
		key:     key,
		version: meta.version,
		field:   field,
	}
	encKey := internalKey.encode()

	var exists bool = true
	if _, err := r.db.Get(encKey); err == gokv.ErrKeyNotFound {
		exists = false
	}
	return exists, nil
}

func (r *RedisDataStruct) HKeys(key []byte) ([][]byte, error) {
	meta, exist, err := r.findMetadata(key, Hash)
	if err != nil {
		return nil, err
	}
	if !exist {
		return nil, gokv.ErrKeyNotFound
	}

	internalKey := hashInternalKey{
		key:     key,
		version: meta.version,
	}

	iterOpts := gokv.DefaultIteratorOptions
	iterOpts.Prefix = internalKey.prefix()
	lenPrefix := len(iterOpts.Prefix)

	iter := r.db.NewIterator(&iterOpts)
	defer iter.Close()

	res := make([][]byte, 0)
	for iter.Seek(key); iter.Valid(); iter.Next() {
		res = append(res, iter.Key()[lenPrefix:])
	}
	return res, nil
}

func (r *RedisDataStruct) HVals(key []byte) ([][]byte, error) {
	meta, exist, err := r.findMetadata(key, Hash)
	if err != nil {
		return nil, err
	}
	if !exist {
		return nil, gokv.ErrKeyNotFound
	}

	internalKey := hashInternalKey{
		key:     key,
		version: meta.version,
	}

	iterOpts := gokv.DefaultIteratorOptions
	iterOpts.Prefix = internalKey.prefix()

	iter := r.db.NewIterator(&iterOpts)
	defer iter.Close()

	res := make([][]byte, 0)
	for iter.Seek(iterOpts.Prefix); iter.Valid(); iter.Next() {
		val, err := iter.Value()
		if err != nil {
			return nil, err
		}
		res = append(res, val)
	}
	return res, nil
}

func (r *RedisDataStruct) HLen(key []byte) int {
	meta, exist, err := r.findMetadata(key, Hash)
	if err != nil || !exist {
		return 0
	}

	return int(meta.size)
}

// hashInternalKey 哈希域值 key 结构
type hashInternalKey struct {
	key     []byte
	version int64
	field   []byte
}

// encodeHashKey hashInternalKey 编码
// key|version|field -> value
func (h *hashInternalKey) encode() []byte {
	lenk, lenf := len(h.key), len(h.field)
	buf := make([]byte, lenk+lenf+8)
	copy(buf[:lenk], h.key)
	binary.LittleEndian.PutUint64(buf[lenk:lenk+8], uint64(h.version))
	copy(buf[lenk+8:], h.field)
	return buf
}

// prefix 获取前缀编码 key|version
func (h *hashInternalKey) prefix() []byte {
	lenk := len(h.key)
	buf := make([]byte, lenk+8)
	copy(buf[:lenk], h.key)
	binary.LittleEndian.PutUint64(buf[lenk:lenk+8], uint64(h.version))
	return buf
}
